// Integration test for GridGraph trait polymorphism

use grid_cut_rs::{GridGraph, GridGraph2D4C, GridGraph2D8C, GridGraph2D4CMT, Segment};

/// Generic function that uses the GridGraph trait
fn compute_flow_generic<G>(graph: &mut G) -> G::Flow
where
    G: GridGraph,
{
    graph.compute_maxflow();
    graph.get_flow()
}

#[test]
fn test_trait_with_2d_4c() {
    let mut graph = GridGraph2D4C::<i32, i32, i32>::new(3, 3).unwrap();
    
    // Set up a simple problem
    let source = graph.node_id(0, 0).unwrap();
    graph.set_terminal_cap(source, 50, 0).unwrap();
    
    let sink = graph.node_id(2, 2).unwrap();
    graph.set_terminal_cap(sink, 0, 50).unwrap();
    
    // Add some neighbor capacities
    for y in 0..3 {
        for x in 0..3 {
            let node = graph.node_id(x, y).unwrap();
            if x < 2 {
                graph.set_neighbor_cap(node, 1, 0, 10).unwrap();
            }
            if y < 2 {
                graph.set_neighbor_cap(node, 0, 1, 10).unwrap();
            }
        }
    }
    
    // Use generic function
    let flow = compute_flow_generic(&mut graph);
    
    // Verify we got some flow
    assert!(flow >= 0);
    
    // Verify segments can be queried
    let source_segment = graph.get_segment(source);
    let sink_segment = graph.get_segment(sink);
    
    // Just verify the types work - actual values depend on algorithm
    assert!(source_segment == Segment::Source || source_segment == Segment::Sink);
    assert!(sink_segment == Segment::Source || sink_segment == Segment::Sink);
}

#[test]
fn test_trait_with_2d_8c() {
    let mut graph = GridGraph2D8C::<i32, i32, i32>::new(3, 3).unwrap();
    
    let source = graph.node_id(0, 0).unwrap();
    graph.set_terminal_cap(source, 50, 0).unwrap();
    
    let sink = graph.node_id(2, 2).unwrap();
    graph.set_terminal_cap(sink, 0, 50).unwrap();
    
    for y in 0..3 {
        for x in 0..3 {
            let node = graph.node_id(x, y).unwrap();
            if x < 2 {
                graph.set_neighbor_cap(node, 1, 0, 10).unwrap();
            }
            if y < 2 {
                graph.set_neighbor_cap(node, 0, 1, 10).unwrap();
            }
        }
    }
    
    // Use generic function
    let flow = compute_flow_generic(&mut graph);
    assert!(flow >= 0);
}

#[test]
fn test_trait_with_2d_4c_mt() {
    let mut graph = GridGraph2D4CMT::<i32, i32, i32>::new(3, 3).unwrap();
    
    let source = graph.node_id(0, 0).unwrap();
    graph.set_terminal_cap(source, 50, 0).unwrap();
    
    let sink = graph.node_id(2, 2).unwrap();
    graph.set_terminal_cap(sink, 0, 50).unwrap();
    
    for y in 0..3 {
        for x in 0..3 {
            let node = graph.node_id(x, y).unwrap();
            if x < 2 {
                graph.set_neighbor_cap(node, 1, 0, 10).unwrap();
            }
            if y < 2 {
                graph.set_neighbor_cap(node, 0, 1, 10).unwrap();
            }
        }
    }
    
    // Use generic function
    let flow = compute_flow_generic(&mut graph);
    assert!(flow >= 0);
}

#[test]
fn test_trait_associated_types() {
    // Verify that associated types work correctly
    fn check_types<G>()
    where
        G: GridGraph,
    {
        // This function just checks that the associated types compile
        let _: Option<G::TerminalCap> = None;
        let _: Option<G::NeighborCap> = None;
        let _: Option<G::Flow> = None;
    }
    
    check_types::<GridGraph2D4C<i32, i32, i32>>();
    check_types::<GridGraph2D8C<i32, i32, i32>>();
    check_types::<GridGraph2D4CMT<i32, i32, i32>>();
}
